use super::*;
pub mod exe;
pub mod pipeline;

pub use exe::*;
pub use pipeline::*;

// pub trait RayonImmutExecutor<I, O>
// where 
//     I:Send + Sync + 'static,
//     O:Send + Sync + 'static,
//     Self:Send + Sync + 'static,
// {
//     type Error:std::error::Error;
//     fn exec<'scope, NE>(
//         &'scope self, 
//         context:&rayon::Scope<'scope>, 
//         input:I, 
//         next_executor:&'scope NE
//     ) -> Result<(), Self::Error>
//     where NE:RayonPipeline<O>;
// }

// pub trait RayonMutExecutor<I, O>
// where 
//     I:Send + Sync + 'static,
//     O:Send + Sync + 'static,
//     Self:Send + Sync + 'static,
// {
//     type Error:std::error::Error;
//     fn exec<'scope, NE>(
//         &'scope mut self, 
//         scope:&rayon::Scope<'scope>,
//         input:I,
//         next_executor:&'scope NE
//     ) -> Result<(), Self::Error>
//     where NE:RayonPipeline<O>;
// }

pub trait RayonPipeline<I>
where 
    I:Send + Sync + 'static,
    Self:Send + Sync + 'static,
{
    type Error:std::error::Error;
    fn exec<'scope>(
        &'scope self, 
        scope:&rayon::Scope<'scope>,
        input:I,
    ) -> Result<(), Self::Error>;
}

pub fn start() -> NoneExecutor { NoneExecutor }

mod rayon_test {
    use std::fmt::Display;

    use super::*;

    #[derive(Debug)]
    struct TestError(String);
    impl Display for TestError {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            write!(f, "{}", &self.0)
        }
    }

    impl From<String> for TestError {
        fn from(value: String) -> Self {
            Self(value)
        }
    }

    impl std::error::Error for TestError { }

    struct Adder;
    impl ImmutExecutor<u64, u64> for Adder {
        type Error = TestError;
        fn exec<'scope, F:FnMut(u64)>(&'scope self, input:u64, mut output:F) -> Result<(), Self::Error> {
            let result = input + 1;
            output(result);
            Ok(())
        }
    }

    struct Printer;
    impl MutExecutor<u64, ()> for Printer {
        type Error = TestError;
        fn exec<'scope, F:FnMut(())>(&'scope mut self, input:u64, mut output:F) -> Result<(), Self::Error> {
            println!("{}", input);
            output(());
            Ok(())
        }
    }

    #[test]
    fn test_exe()  {
        use rayon::ThreadPoolBuilder;
        let pool = ThreadPoolBuilder::new().num_threads(2).build().unwrap();
        let _ = pool.scope(|s|{
            from_scope_and_iter::<u64, _>(s, vec![1u64, 2, 3, 4])
                .pipelined_immut(Adder)
                .pipelined_immut(Adder)
                .pipelined_mut(Printer)
                .run(); 
        });
    }
}